package cn.sunxyz.aop.plugin;

import cn.sunxyz.aop.annotation.Aop;
import cn.sunxyz.aop.aspect.Aspect;
import cn.sunxyz.aop.proxy.ProxyFactory;
import cn.sunxyz.common.utils.StringUtil;
import cn.sunxyz.common.utils.reflect.ClassUtil;
import cn.sunxyz.common.utils.reflect.ReflectionUtil;
import cn.sunxyz.core.bean.plugin.AbstractPlugin;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by yangrd on 2017/5/25.
 */
public class AopPlugin extends AbstractPlugin {

    Map<Aop, Aspect> aopAspectMap = new HashMap<>();

    @Override
    public void before(Function<Class<? extends Annotation>, List<Class<?>>> listClassByAnnotation) {
        List<Class<?>> aopIntercepts = listClassByAnnotation.apply(Aop.class);
        for (Class<?> cls : aopIntercepts) {
            if (ClassUtil.getAllInterfaces(cls).contains(Aspect.class)) {
                Aop aop = cls.getAnnotation(Aop.class);
                Class<Aspect> aspectCls = (Class<Aspect>) cls;
                aopAspectMap.put(aop, ReflectionUtil.invokeConstructor(aspectCls));
            }
        }
    }

    @Override
    public Object createTarget(Class<?> targetClazz, Object target) {
        String pkg = ClassUtil.getPackageName(targetClazz);
        String cls = targetClazz.getSimpleName();
        Map<Integer, Aspect> sortAspectsMap = aopAspectMap.entrySet().stream().filter(aopAspectEntry -> filter(aopAspectEntry.getKey(), pkg, cls)).collect(Collectors.toMap(aopAspectEntry -> aopAspectEntry.getKey().sort(), aopAspectEntry -> aopAspectEntry.getValue()));
        return sortAspectsMap.size() > 0 ? ProxyFactory.getProxy(targetClazz, sortAspectsMap) : (target == null ? ReflectionUtil.invokeConstructor(targetClazz) : target);
    }

    /**
     * pkg 为空则忽略(不为空调用contains) cls 为空则忽略(不为空调用contains)
     */
    private boolean filter(Aop aop, String pkg, String cls) {
        if (StringUtil.isNotEmpty(aop.pkg())) {
            if (pkg.contains(aop.pkg())) {
                if (StringUtil.isNotEmpty(aop.cls())) {
                    if (cls.contains(aop.cls())) {
                        return true;
                    }
                }
            }
        } else {
            if (StringUtil.isNotEmpty(aop.cls())) {
                if (cls.contains(aop.cls())) {
                    return true;
                }
            } else {
                return true;
            }
        }
        return false;
    }

}
